﻿using AiMoRhino.ScriptInstance.CustomGetter;
using Rhino.DocObjects;
using Rhino.Geometry;
using Rhino.Input.Custom;
using System;
using System.Collections.Generic;
using System.Linq;

namespace AiMoRhino.ScriptInstance.LinkSelect
{
    class LinkedMultipleItem : LinkedItemBase
    {
        public override void ClearLink()
        {
            guids = Array.Empty<Guid>();
        }
        public override bool IsMultiple => true;
        Guid[] guids = Array.Empty<Guid>();
        public override IEnumerable<Guid> AllIDs => guids;
        public override bool HasLinkedObject => guids.Length > 0;

        public RhinoObject[] ResultRhinoObjs { get; private set; } = Array.Empty<RhinoObject>();
        public InstanceObject[] ResultInstanceObjs { get; private set; }
        public Point3d[] ResultPoints { get; private set; }
        public Polyline[] ResultPolylines { get; private set; }
        public Circle[] ResultCircles { get; private set; }
        public Line[] ResultLines { get; private set; }
        public Curve[] ResultCurves { get; private set; }
        public Mesh[] ResultMeshes { get; private set; }
        public Brep[] ResultBreps { get; private set; }
        public Extrusion[] ResultExtrusions { get; private set; }
        public Surface[] ResultSurfaces { get; private set; }

        public LinkedMultipleItem(LinkType currentLinkType) : base(currentLinkType)
        {
        }

        public override bool BuildLink()
        {
            switch (CurrentLinkType)
            {
                case LinkType.RhinoObject:
                    if (GetMultipleObject(out RhinoObject[] objs, ObjectType.AnyObject, "RhinoObjects", new GetObject()))
                    {
                        guids = objs.Select(x => x.Id).ToArray();
                    }
                    break;
                case LinkType.InstanceObject:
                    if (GetMultipleObject(out RhinoObject[] iobjs, ObjectType.InstanceReference, "Instance References", new GetObject()))
                    {
                        guids = iobjs.Select(x => x.Id).ToArray();
                    }
                    break;
                case LinkType.Point3d:
                    if (GetMultipleObject(out RhinoObject[] ptobjs, ObjectType.Point, "Point3ds", new GetObject()))
                    {
                        guids = ptobjs.Select(x => x.Id).ToArray();
                    }
                    break;
                case LinkType.Polyline:
                    if (GetMultipleObject(out RhinoObject[] plObjs, ObjectType.Curve, "Polylines", new GetPolylineObject()))
                    {
                        guids = plObjs.Select(x => x.Id).ToArray();
                    }
                    break;
                case LinkType.Circle:
                    if (GetMultipleObject(out RhinoObject[] cirObjs, ObjectType.Curve, "Circles", new GetCircleObject()))
                    {
                        guids = cirObjs.Select(x => x.Id).ToArray();
                    }
                    break;
                case LinkType.Line:
                    if (GetMultipleObject(out RhinoObject[] liObjs, ObjectType.Curve, "Lines", new GetLineObject()))
                    {
                        guids = liObjs.Select(x => x.Id).ToArray();
                    }
                    break;
                case LinkType.Curve:
                    if (GetMultipleObject(out RhinoObject[] crvObjs, ObjectType.Curve, "Curves", new GetObject()))
                    {
                        guids = crvObjs.Select(x => x.Id).ToArray();
                    }
                    break;
                case LinkType.Mesh:
                    if (GetMultipleObject(out RhinoObject[] meshObjs, ObjectType.Mesh, "Meshes", new GetObject()))
                    {
                        guids = meshObjs.Select(x => x.Id).ToArray();
                    }
                    break;
                case LinkType.Extrusion:
                    if (GetMultipleObject(out RhinoObject[] extObjs, ObjectType.Extrusion, "Extrusions", new GetObject()))
                    {
                        guids = extObjs.Select(x => x.Id).ToArray();
                    }
                    break;
                case LinkType.Surface:
                    if (GetMultipleObject(out RhinoObject[] srfObjs, ObjectType.Surface, "Surfaces", new GetObject()))
                    {
                        guids = srfObjs.Select(x => x.Id).ToArray();
                    }
                    break;
            }
            return guids.Length > 0;
        }

        public override bool GetLinkedGeometry()
        {
            if (guids.Length > 0)
            {
                switch (CurrentLinkType)
                {
                    case LinkType.RhinoObject:
                        ResultRhinoObjs = guids.Select(x => Find(x)).Where(x => x != null).ToArray();
                        return ResultRhinoObjs.Length > 0;
                    case LinkType.InstanceObject:
                        ResultInstanceObjs = guids.Select(x => Find(x)).Where(x => x is InstanceObject).Cast<InstanceObject>().ToArray();
                        return ResultInstanceObjs.Length > 0;
                    case LinkType.Point3d:
                        ResultPoints = ToPoints();
                        return ResultPoints.Length > 0;
                    case LinkType.Polyline:
                        ResultPolylines = ToPolylines();
                        return ResultPolylines.Length > 0;
                    case LinkType.Circle:
                        ResultCircles = ToCircles();
                        return ResultCircles.Length > 0;
                    case LinkType.Line:
                        ResultLines = ToLines();
                        return ResultLines.Length > 0;
                    case LinkType.Curve:
                        ResultCurves = ToCurves();
                        return ResultCurves.Length > 0;
                    case LinkType.Mesh:
                        ResultMeshes = ToMeshes();
                        return ResultMeshes.Length > 0;
                    case LinkType.Brep:
                        ResultBreps = ToBreps();
                        return ResultBreps.Length > 0;
                    case LinkType.Extrusion:
                        ResultExtrusions = ToExtrusions();
                        return ResultExtrusions.Length > 0;
                    case LinkType.Surface:
                        ResultSurfaces = ToSurfaces();
                        return ResultSurfaces.Length > 0;
                }
            }
            return false;
        }


        Surface[] ToSurfaces()
        {
            List<Surface> result = new List<Surface>();
            foreach (RhinoObject robj in guids.Select(x => Find(x)))
            {
                if (robj is BrepObject subObj && subObj.BrepGeometry.Surfaces.Count == 1)
                {
                    result.Add(subObj.BrepGeometry.Surfaces[0]);
                }
            }
            return result.ToArray();
        }

        Extrusion[] ToExtrusions()
        {
            List<Extrusion> result = new List<Extrusion>();
            foreach (RhinoObject robj in guids.Select(x => Find(x)))
            {
                if (robj is ExtrusionObject subObj)
                {
                    result.Add(subObj.ExtrusionGeometry);
                }
            }
            return result.ToArray();
        }
        Brep[] ToBreps()
        {
            List<Brep> result = new List<Brep>();
            foreach (RhinoObject robj in guids.Select(x => Find(x)))
            {
                if (robj is BrepObject subObj)
                {
                    result.Add(subObj.BrepGeometry);
                }
            }
            return result.ToArray();
        }

        Mesh[] ToMeshes()
        {
            List<Mesh> result = new List<Mesh>();
            foreach (RhinoObject robj in guids.Select(x => Find(x)))
            {
                if (robj is MeshObject subObj)
                {
                    result.Add(subObj.MeshGeometry);
                }
            }
            return result.ToArray();
        }

        Curve[] ToCurves()
        {
            List<Curve> result = new List<Curve>();
            foreach (RhinoObject robj in guids.Select(x => Find(x)))
            {
                if (robj is CurveObject curveObj)
                {
                    result.Add(curveObj.CurveGeometry);
                }
            }
            return result.ToArray();
        }
        Line[] ToLines()
        {
            List<Line> result = new List<Line>();
            foreach (RhinoObject robj in guids.Select(x => Find(x)))
            {
                if (robj is CurveObject curveObj &&
                    curveObj.CurveGeometry.IsLinear())
                {
                    result.Add(new Line(curveObj.CurveGeometry.PointAtStart, curveObj.CurveGeometry.PointAtEnd));
                }
            }
            return result.ToArray();
        }
        Circle[] ToCircles()
        {
            List<Circle> result = new List<Circle>();
            foreach (RhinoObject robj in guids.Select(x => Find(x)))
            {
                if (robj is CurveObject curveObj &&
                    curveObj.CurveGeometry.TryGetCircle(out Circle crv))
                {
                    result.Add(crv);
                }
            }
            return result.ToArray();
        }

        Polyline[] ToPolylines()
        {
            List<Polyline> result = new List<Polyline>();
            foreach (RhinoObject robj in guids.Select(x => Find(x)))
            {
                if (robj is CurveObject curveObj &&
                    curveObj.CurveGeometry.TryGetPolyline(out Polyline crv))
                {
                    result.Add(crv);
                }
            }
            return result.ToArray();
        }
        Point3d[] ToPoints()
        {
            List<Point3d> points = new List<Point3d>();
            foreach (RhinoObject robj in guids.Select(x => Find(x)))
            {
                if (robj is PointObject ptObj && ptObj.PointGeometry != null)
                {
                    points.Add(ptObj.PointGeometry.Location);
                }
            }
            return points.ToArray();
        }

    }
}
